﻿using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace WinRT.Triggers.Test
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Windows.UI.Core;
    using Windows.ApplicationModel.Core;
    using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;

    [TestClass]
    public class AttachableCollectionTests
    {
        public void ExecuteOnUIThread(Windows.UI.Core.DispatchedHandler action)
        {
            // Not ideal but best I can do based on what I know right now!
            // any assertions that fail will just get exposed as a generic Exception - you'll have to debug to find out what it is exactly.
            var task = CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, action).AsTask();

            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                throw ex.InnerException;
            }
        }

        [TestMethod]
        public void ShouldAttachContainedItemsWhenAdded()
        {
            ExecuteOnUIThread(() =>
                                  {
                                      var col = new AttachableCollection<TestAttachableObject>();

                                      var attachedTo = new Grid();

                                      col.Attach(attachedTo);

                                      var elem1 = new TestAttachableObject();
                                      col.Add(elem1);

                                      Assert.IsTrue(elem1.IsAttached);
                                      Assert.AreSame(attachedTo, elem1.AssociatedObject);
                                  });
        }

        [TestMethod]
        public void ShouldUnattachAllContainedItemsWhenCleared()
        {
            ExecuteOnUIThread(() =>
                {
                    var col = new AttachableCollection<TestAttachableObject>();

                    // Attach the collection
                    col.Attach(new Grid());

                    var elem1 = new TestAttachableObject();
                    var elem2 = new TestAttachableObject();
                    var elem3 = new TestAttachableObject();

                    col.Add(elem1);
                    col.Add(elem2);
                    col.Add(elem3);

                    col.Clear();

                    Assert.IsFalse(elem1.IsAttached);
                    Assert.IsFalse(elem2.IsAttached);
                    Assert.IsFalse(elem3.IsAttached);
                });
        }

        private class TestAttachableObject : FrameworkElement, IAssociatableElement
        {
            public bool IsAttached { get; set; }

            public void Attach(FrameworkElement obj)
            {
                if (this.IsAttached)
                {
                    Assert.Fail("Duplicate attach detected");
                }

                this.AssociatedObject = obj;

                this.IsAttached = true;
            }

            public void Detach()
            {
                if (!this.IsAttached)
                {
                    Assert.Fail("Detach without attach detected");
                }

                this.AssociatedObject = null;

                this.IsAttached = false;
            }

            public FrameworkElement AssociatedObject { get; private set; }
        }
    }
}
